package me.zhengjie.modules.rcon;

import org.springframework.stereotype.Component;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.Random;

@Component
public class RCONClient {
    private Socket socket;
    private DataInputStream input;
    private DataOutputStream output;
    private int lastRequestId;

    public void connect(String host, int port) throws IOException {
        socket = new Socket(host, port);
        input = new DataInputStream(socket.getInputStream());
        output = new DataOutputStream(socket.getOutputStream());
    }

    public boolean authenticate(String password) throws IOException {
        int requestId = new Random().nextInt();
        byte[] packet = buildPacket(requestId, 3, password);
        output.write(packet);
        output.flush();

        Packet response = readPacket();
        return response.requestId == requestId && response.type == 2;
    }

    public String sendCommand(String command) throws IOException {
        int requestId = new Random().nextInt();
        byte[] packet = buildPacket(requestId, 2, command);
        output.write(packet);
        output.flush();

        StringBuilder response = new StringBuilder();
//        while (true) {
//            Packet p = readPacket();
//            if (p.requestId != requestId) break;
//            response.append(p.payload);
//        }
        Packet p = readPacket();
        response.append(p.payload);
        return response.toString();
    }

    private byte[] buildPacket(int requestId, int type, String payload) {
        byte[] payloadBytes = payload.getBytes(StandardCharsets.UTF_8);
        int length = 4 + 4 + payloadBytes.length + 2;
        ByteBuffer buffer = ByteBuffer.allocate(4 + length)
                .order(ByteOrder.LITTLE_ENDIAN);

        buffer.putInt(length);
        buffer.putInt(requestId);
        buffer.putInt(type);
        buffer.put(payloadBytes);
        buffer.put((byte) 0);
        buffer.put((byte) 0);
        return buffer.array();
    }

    private Packet readPacket() throws IOException {
        // 读取长度字段（4字节小端）
        byte[] lengthBytes = new byte[4];
        input.readFully(lengthBytes);
        int length = ByteBuffer.wrap(lengthBytes)
                .order(ByteOrder.LITTLE_ENDIAN)
                .getInt();

        // 读取剩余数据
        byte[] packetData = new byte[length];
        input.readFully(packetData);
        ByteBuffer buffer = ByteBuffer.wrap(packetData)
                .order(ByteOrder.LITTLE_ENDIAN);

        Packet packet = new Packet();
        packet.requestId = buffer.getInt();
        packet.type = buffer.getInt();
        
        // 提取有效载荷（排除最后的两个空字节）
        int payloadLength = buffer.remaining() - 2;
        byte[] payloadBytes = new byte[payloadLength];
        buffer.get(payloadBytes);
        packet.payload = new String(payloadBytes, StandardCharsets.UTF_8);
        
        // 跳过最后的两个空字节
        buffer.position(buffer.position() + 2);
        return packet;
    }

    public void close() {
        try {
            if (input != null) input.close();
            if (output != null) output.close();
            if (socket != null) socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static class Packet {
        int requestId;
        int type;
        String payload;
    }

    public static void main(String[] args) {
        RCONClient client = new RCONClient();
        try {
            client.connect("59.47.231.71", 25575);
            if (client.authenticate("kk507507")) {
                String response = client.sendCommand("Z2l2ZSBzdGVhbV83NjU2MTE5ODA5OTE4NzY2MCBjc2pqMTEzIDEwCg==");
                System.out.println("Server response: " + response);
            } else {
                System.out.println("Authentication failed");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            client.close();
        }
    }
}